/*
 * =====================================================================================
 *
 *       Filename:  poll.cpp
 *
 *    Description: 	poll for demultiplex 
 *
 *        Version:  1.0
 *        Created:  08/14/2012 11:08:42 AM
 *       Revision:  none
 *       Compiler:  gcc/g++
 *
 *         Author:  wangtengchao , wangtengchao AT gmail.com
 *   Organization:  
 *
 * =====================================================================================
 */

#include "poll.h"
#include "defines.h"
#include "netHelp.h"
#include "dispatcher.h"
#ifdef NET_DEBUG
    #include <cstdio>
#endif
using namespace inm::net;

Poll::Poll()
    :vPollfd_(InitialMaxFd),
      maxUsedFdIndex_(0),
      lowestFreeFdIndex_(0)
{
    for(int i = 0;i<InitialMaxFd;i++)
        vPollfd_[i].fd = -1;
     isRunning_ = false;
    //can set systemMaxFd by system environment
}
Poll::~Poll()
{//fd will delete by tcpconnect's deconstructor
}


void Poll::handleEvents(int timeout)
{
    int ret = 0;
    isRunning_ = true;
    while(true)
    {
        dispatcher_->doTasks();
        if(isRunning_ && (ret=poll(&(*vPollfd_.begin()), vPollfd_.size(),timeout )) > 0)
        {
            for(int i=0;i<=maxUsedFdIndex_;i++)
            {//<=   not  <
                if(vPollfd_[i].revents != 0)
                {//this fd have occur
                    EventHandlerPtr it = dispatcher_->getEventHandlerByFd(vPollfd_[i].fd);
                    assert(it.get() != NULL);
                    if(vPollfd_[i].revents & POLLERR)
                        it->handleClose();
                    else
                        if(vPollfd_[i].revents & POLLIN)
                        {//use read 0 to close
                            it->handleRead();
                        }
                        else
                         if(vPollfd_[i].revents & POLLOUT)
                         {
                             it->handleWrite();
                         }
                }
            }
        }
		else
		{
            if(!isRunning_)
				break;//close server
		}
    }
}


void Poll::registerEvent(int fd, const short &et)
{
#ifdef NET_BUG
    printf("register %d \n",et);
#endif
    vPollfd_[lowestFreeFdIndex_].fd = fd;
    if(et & ACCEPT_EVENT)
    {
        vPollfd_[lowestFreeFdIndex_].events = POLLIN;
    }
    else
    {
        short ev = 0;
        if(et & READ_EVENT)
            ev |= POLLIN;
        if(et & WRITE_EVENT)
            ev |= POLLOUT;
        vPollfd_[lowestFreeFdIndex_].events = ev;
    }
    //set new lowestFreeFdIndex_ and maxUsedFdIndex_(if needed)
    if(lowestFreeFdIndex_ >= maxUsedFdIndex_)
    {//need  change maxUsedFreeIndex_
        maxUsedFdIndex_ = lowestFreeFdIndex_;
        lowestFreeFdIndex_ = maxUsedFdIndex_ + 1;
    }
    else
    {//maxUsedFdIndex_ is larger than lowestFreeFdIndex_
        //find next lowest free
        int i = 0;
        for(i = lowestFreeFdIndex_;i<maxUsedFdIndex_;i++)
            if(vPollfd_[i].fd == -1)
            {
                lowestFreeFdIndex_ = i;
                break;
            }
        //no free pollfd in lowestFreeFdIndex+1 ~ maxUsedFdIndex-1
        if(i == maxUsedFdIndex_)
            lowestFreeFdIndex_ = maxUsedFdIndex_ + 1;
    }

}

void Poll::updateEvent(int fd, const short &et)
{
    size_t s = vPollfd_.size();
    int i=0;
    for(;i<s;i++)
        if(vPollfd_[i].fd == fd)
            break;
    if(i < s)
    {//find
        if(et & ACCEPT_EVENT)
        {
            vPollfd_[i].events = POLLRDNORM;
        }
        else
        {
            short ev = 0;
            if(et & READ_EVENT)
                ev |= POLLIN;
            if(et & WRITE_EVENT)
                ev |= POLLOUT;
            vPollfd_[i].events = ev;
        }
        if(vPollfd_[i].events == 0)//have delete all events
            removeEvent(fd,0);
    }

}

void Poll::removeEvent(int fd, const short &et)
{
   size_t s = vPollfd_.size();
   int i=0;
   for(i=0;i<s;i++)
       if(vPollfd_[i].fd == fd)
           break;
   if(i<s)
   {//find
       vPollfd_[i].fd = -1;
       if(lowestFreeFdIndex_ > i)
           lowestFreeFdIndex_ = i;
       if(maxUsedFdIndex_ == i)
           maxUsedFdIndex_--;
   }

}

